package com.bmps.springcloud.insuredmicroservice.util.calculate;

import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;

import javax.validation.constraints.NotEmpty;
import java.util.*;

/**
 * description:
 * 计算利率
 *
 * @author jackdaw
 * @date 2019-12-19 17:40
 */
public class CalculateUtil {
    /**
     * 复利
     */
    public static String COMPOUND = "C";
    /**
     * 单利
     */
    public static String SIMPLE = "S";

    public static double getMultiResultRateMS(@NotEmpty List<Map<String, Object>> rateInfos, String scType, String interest, Date startDate, Date balanceDate) {
        if (startDate.after(balanceDate)) {
            return 0;
        }
        List<String> rates = getDailyRates(rateInfos, interest, scType, "D", startDate, balanceDate);
        if (CollectionUtils.isEmpty(rates)) {
            return 0;
        }
        double resultRate = 0.0;
        if (StringUtils.equals(SIMPLE, scType)) {
            for (String rate : rates) {
                resultRate += Double.parseDouble(rate);
            }
        } else if (StringUtils.equals(COMPOUND, scType)) {
            resultRate = 1;
            for (String rate : rates) {
                if (StringUtils.isBlank(rate)) {
                    return -1;
                }
                double number = Double.parseDouble(rate);
                if (number == 0) {
                    return -1;
                }
                resultRate *= number;
            }
            resultRate -= 1;
        }
        return resultRate;
    }

    private static List<String> getDailyRates(@NotEmpty List<Map<String, Object>> rateInfos, String rateType,
                                              String transType, String intervalType, Date originStartDate, Date balanceDate) {
        List<String> result = new ArrayList<>(rateInfos.size());
        int i = 0;
        Date date = null;
        for (Map<String, Object> rateInfo : rateInfos) {
            double value = (double) rateInfo.get("rate");
            Date startDate = (Date) rateInfo.get("ed");
            if (i == 0) {
                date = originStartDate;
            }
            if (calInterval(startDate, balanceDate, intervalType) > 0) {
                int interval = calInterval(date, startDate, intervalType);
                if (interval > 0) {
                    double rate = transAccRate(date, startDate, value, rateType, transType, intervalType);
                    result.add(String.valueOf(getIntvRateMS(interval, rate, transType)));
                }
                date = startDate;
            } else {
                int interval = calInterval(date, balanceDate, intervalType);
                if (interval > 0) {
                    double rate = transAccRate(date, balanceDate, value, rateType, transType, intervalType);
                    result.add(String.valueOf(getIntvRateMS(interval, rate, transType)));
                }
                break;
            }
            i++;
        }
        return result;
    }

    public static int calInterval(Date startDate, Date endDate, String unit) {
        int interval = 0;
        GregorianCalendar sCalendar = new GregorianCalendar();
        sCalendar.setTime(startDate);
        int sYears = sCalendar.get(Calendar.YEAR);
        int sMonths = sCalendar.get(Calendar.MONTH);
        int sDays = sCalendar.get(Calendar.DAY_OF_MONTH);
        GregorianCalendar eCalendar = new GregorianCalendar();
        eCalendar.setTime(endDate);
        int eYears = eCalendar.get(Calendar.YEAR);
        int eMonths = eCalendar.get(Calendar.MONTH);
        int eDays = eCalendar.get(Calendar.DAY_OF_MONTH);
        if (unit.equals("Y")) {
            interval = eYears - sYears;
            if (eMonths < sMonths) {
                interval--;
            } else {
                if (eMonths == sMonths && eDays < sDays) {
                    interval--;
                    // 如果同是2月，校验润年问题
                    if (eMonths == 1) {
                        // 如果起始年是润年，终止年不是润年
                        if (isLeapYear(sYears) && isLeapYear(eYears)) {
                            // 如果终止年不是润年，且2月的最后一天28日，那么补一
                            if (eDays == 28) {
                                interval++;
                            }
                        }
                    }
                }
            }
        }
        if (unit.equals("M")) {
            interval = eYears - sYears;
            interval *= 12;
            interval += eMonths - sMonths;
            if (eDays < sDays) {
                interval--;
                // eDays如果是月末，则认为是满一个月
                int maxDate = eCalendar.getActualMaximum(Calendar.DATE);
                if (eDays == maxDate) {
                    interval++;
                }
            }
        }
        if (unit.equals("D")) {
            sCalendar.set(sYears, sMonths, sDays);
            eCalendar.set(eYears, eMonths, eDays);
            long lInterval = (eCalendar.getTime().getTime() - sCalendar
                    .getTime().getTime()) / 86400000;
            interval = (int) lInterval;
        }
        return interval;
    }

    public static boolean isLeapYear(long prolepticYear) {
        return ((prolepticYear & 3) == 0) && ((prolepticYear % 100) != 0 || (prolepticYear % 400) == 0);
    }

    public static int calLeapDaysBetween(Date startDate, Date endDate) {
        if (startDate.compareTo(endDate) > 0) {
            Date temp = endDate;
            endDate = startDate;
            startDate = temp;
        }
        Date nowDate = startDate;
        Date nextDate;
        int tLeapCount = 0;
        Calendar calendar = Calendar.getInstance();
        while ((nowDate.compareTo(endDate)) < 0) {
            calendar.setTime(nowDate);
            int year = calendar.get(Calendar.YEAR);
            calendar.set(year + 1, 0, 1);
            nextDate = calendar.getTime();
            if (isLeapYear(year)) {
                tLeapCount += calInterval(nowDate, (endDate.compareTo(nextDate) > 0) ? nextDate : endDate, "D");
            }
            nowDate = nextDate;
        }
        ;
        return tLeapCount;
    }

    public static double transAccRate(Date startDate, Date endDate, double originRate, String originRateType,
                                      String transType, String destRateType) {

        int tCount = Math.abs(calInterval(startDate, endDate, "D"));
        double tYearDays;
        if (tCount != 0) {
            int tLeapDays = calLeapDaysBetween(startDate, endDate);
            tYearDays = 365 * 366 * tCount / (double) (tLeapDays * 365 + (tCount - tLeapDays) * 366);
        } else {
            tYearDays = 365;
        }

        double DestRate = 0;
        double aPower;

        // 复利处理
        if (transType.equals("C")) {

            // 年复利转换
            if (originRateType.equals("Y")) {
                // translate to year
                if (destRateType.equals("Y")) {
                    DestRate = originRate;
                }
                // translate to month
                else if (destRateType.equals("M")) {
                    aPower = 1.0 / 12.0;
                    DestRate = Math.pow(1 + originRate, aPower) - 1;
                }
                // translate to day
                else if (destRateType.equals("D")) {
//					aPower = 1.0 / 365.0;// for NCL Modified by lizhuo
                    aPower = 1.0 / tYearDays;// shit
                    // aPower = 1.0 / Double.parseDouble(SysConst.DAYSOFYEAR);
                    DestRate = Math.pow(1 + originRate, aPower) - 1;
                }
            }
            // 月复利转换
            else if (originRateType.equals("M")) {
                // translate to month
                if (destRateType.equals("M")) {
                    DestRate = originRate;
                }
                // translate to year
                else if (destRateType.equals("Y")) {
                    aPower = 12;
                    DestRate = Math.pow(1 + originRate, aPower) - 1;
                }
                // translate to day
                else if (destRateType.equals("D")) {
                    aPower = 1.0 / 30.0;
                    DestRate = Math.pow(1 + originRate, aPower) - 1;
                }
            }
            // 日复利转换
            else if (originRateType.equals("D")) {
                // translate to day
                if (destRateType.equals("D")) {
                    DestRate = originRate;
                }
                // translate to month
                else if (destRateType.equals("M")) {
                    aPower = 30;
                    DestRate = Math.pow(1 + originRate, aPower) - 1;
                }
                // translate to year
                else if (destRateType.equals("Y")) {
                    aPower = tYearDays;
                    DestRate = Math.pow(1 + originRate, aPower) - 1;
                }
            }
        }
        // 单利处理
        else if (transType.equals("S")) {
            // 年单利转换
            if (originRateType.equals("Y")) {
                // translate to year
                if (destRateType.equals("Y")) {
                    DestRate = originRate;
                }
                // translate to month
                else if (destRateType.equals("M")) {
                    DestRate = originRate / 12;
                }
                // translate to day
                else if (destRateType.equals("D")) {
                    DestRate = originRate / tYearDays;
                }
            }
            // 月单利转换
            else if (originRateType.equals("M")) {
                // translate to month
                if (destRateType.equals("M")) {
                    DestRate = originRate;
                }
                // translate to year
                else if (destRateType.equals("Y")) {
                    DestRate = originRate * 12;
                }
                // translate to day
                else if (destRateType.equals("D")) {
                    DestRate = originRate / 30;
                }
            }
            // 日单利转换
            else if (originRateType.equals("D")) {
                // translate to day
                if (destRateType.equals("D")) {
                    DestRate = originRate;
                }
                // translate to month
                else if (destRateType.equals("M")) {
                    DestRate = originRate * 30;
                }
                // translate to year
                else if (destRateType.equals("Y")) {
                    DestRate = originRate * tYearDays;
                }
            }
        }
        return DestRate;
    }

    private static double getIntvRateMS(int interval, double rate,
                                        String transType) {
        double intvRate = 0.0;

        if (transType.equals("S")) {
            intvRate = rate * interval;
//			aIntvRate = (1+aRate) * aInterval;
        } else if (transType.equals("C")) {
//			aIntvRate = java.lang.Math.pow(1 + aRate, aInterval) - 1;
            intvRate = Math.pow(1 + rate, interval);
        } else {

        }
        return intvRate;
    }

    public static void main(String[] args) {
        String[] doubles = new String[3];
        System.out.println(doubles[1] + "*********" + doubles.length);
    }
}
